/******************************************************************************
 cnome: A C++ source "genes" discover. :-)

 See more details at:

   http://www.codeplex.com/cnome

 The original author site is at: http://www.alexandre-barbosa.com/

 Copyright (c) 2008 Alexandre Barbosa.
 Distributed under the MIT License. (See accompanying file LICENSE-MIT.txt 
 or at http://www.codeplex.com/cnome/license)
 ******************************************************************************/

#ifndef DIRECTIVE_PD_H
#define DIRECTIVE_PD_H

#include <list>

#include "directive_base.h"
#include "variables.h"

namespace cnome { namespace directive {
    template <typename ParserT>
    struct pdi
    :   public boost::spirit::classic::unary<ParserT, boost::spirit::classic::parser<pdi<ParserT> > > 
    {
        typedef pdi<ParserT>                     self_t;
        typedef boost::spirit::classic::unary_parser_category           parser_category_t;
        typedef boost::spirit::classic::unary<ParserT, boost::spirit::classic::parser<self_t> > base_t;

        pdi(ParserT const& p)
        : base_t(p) {}

        template <typename ScannerT>
        typename boost::spirit::classic::parser_result<self_t, ScannerT>::type
        parse(ScannerT const& scan) const
        {
            typedef typename boost::spirit::classic::parser_result<self_t, ScannerT>::type result_t;
            return impl::drt_parser_parse<result_t>
                (*this, scan, scan);
        }

        const char* MyName() const { return "pdi"; }

        template <typename ScannerT>
        inline void
        deriv_action_before_parse(
            ScannerT const& scan) const
        {
			previousParameterType.push_back(var::parameterType);
			var::parameterType = var::method_parameter;
            var::prms.clear();
            var::prmVars.clear();
        }

        template <typename ScannerT>
        inline void
        deriv_action_after_parse(
            ScannerT const& scan) const
        {
			var::parameterType = previousParameterType.back();
			previousParameterType.pop_back();
        }

		mutable std::list<eParameterType> previousParameterType;
    };

    template <typename ParserT>
    struct pdf
    :   public boost::spirit::classic::unary<ParserT, boost::spirit::classic::parser<pdf<ParserT> > > 
    {
        typedef pdf<ParserT>                     self_t;
        typedef boost::spirit::classic::unary_parser_category           parser_category_t;
        typedef boost::spirit::classic::unary<ParserT, boost::spirit::classic::parser<self_t> > base_t;

        pdf(ParserT const& p)
        : base_t(p) {}

        template <typename ScannerT>
        typename boost::spirit::classic::parser_result<self_t, ScannerT>::type
        parse(ScannerT const& scan) const
        {
            typedef typename boost::spirit::classic::parser_result<self_t, ScannerT>::type result_t;
            return impl::drt_parser_parse<result_t>
                (*this, scan, scan);
        }

        const char* MyName() const { return "pdf"; }

        template <typename ScannerT>
        inline void
        deriv_action_before_parse(
            ScannerT const& scan) const
        {
			previousParameterType.push_back(var::parameterType);
			var::parameterType = method_parameter;
            var::l_prms.push_back(var::prms);
            var::prms.clear();
            var::l_prmVars.push_back(var::prmVars);
            var::prmVars.clear();
        }

        template <typename ScannerT>
        inline void
        deriv_action_after_parse(
            ScannerT const& scan) const
        {
            var::prms=var::l_prms.back();
            var::l_prms.pop_back();
            var::prmVars=var::l_prmVars.back();
            var::l_prmVars.pop_back();
			var::parameterType = previousParameterType.back();
			previousParameterType.pop_back();
        }

		mutable std::list<eParameterType> previousParameterType;

    };

    template <typename ParserT>
    struct pdl
    :   public boost::spirit::classic::unary<ParserT, boost::spirit::classic::parser<pdl<ParserT> > > 
    {
        typedef pdl<ParserT>                     self_t;
        typedef boost::spirit::classic::unary_parser_category           parser_category_t;
        typedef boost::spirit::classic::unary<ParserT, boost::spirit::classic::parser<self_t> > base_t;

        pdl(ParserT const& p)
        : base_t(p) {}

        template <typename ScannerT>
        typename boost::spirit::classic::parser_result<self_t, ScannerT>::type
        parse(ScannerT const& scan) const
        {
            typedef typename boost::spirit::classic::parser_result<self_t, ScannerT>::type result_t;
            return impl::drt_parser_parse<result_t>
                (*this, scan, scan);
        }

        const char* MyName() const { return "pdl"; }

        template <typename ScannerT>
        inline void
        deriv_action_before_parse(
            ScannerT const& scan) const
        {
			previousParameterType.push_back(var::parameterType);
			var::parameterType = method_parameter;
			var::prmLevel++;
			if (var::prmLevel + 1 > static_cast<int>(var::prmNums.capacity()))
			{
				var::prmNums.resize(var::prmNums.size() + 5);
			}
			if (var::prmLevel + 1 > static_cast<int>(var::prmNums.size()))
				var::prmNums.push_back(0);
			else
  			    var::prmNums[var::prmLevel] = 0;
        }

        template <typename ScannerT>
        inline void
        deriv_action_after_parse(
            ScannerT const& scan) const
        {
			var::prmLevel--;
			var::parameterType = previousParameterType.back();
			previousParameterType.pop_back();
        }

		mutable std::list<eParameterType> previousParameterType;
    };

    template <typename ParserT>
    struct pdt
    :   public boost::spirit::classic::unary<ParserT, boost::spirit::classic::parser<pdt<ParserT> > > 
    {
        typedef pdt<ParserT>                     self_t;
        typedef boost::spirit::classic::unary_parser_category           parser_category_t;
        typedef boost::spirit::classic::unary<ParserT, boost::spirit::classic::parser<self_t> > base_t;

        pdt(ParserT const& p)
        : base_t(p), previousParameterType() {}

        template <typename ScannerT>
        typename boost::spirit::classic::parser_result<self_t, ScannerT>::type
        parse(ScannerT const& scan) const
        {
            typedef typename boost::spirit::classic::parser_result<self_t, ScannerT>::type result_t;
            return impl::drt_parser_parse<result_t>
                (*this, scan, scan);
        }

        const char* MyName() const { return "pdt"; }

        template <typename ScannerT>
        inline void
        deriv_action_before_parse(
            ScannerT const& scan) const
        {
			previousParameterType.push_back(template_parameter);
			var::parameterType = template_parameter;
            var::l_tmplPrms.push_back(var::tmplPrms);
            var::tmplPrms.clear();
            var::l_tmplPrmVars.push_back(var::tmplPrmVars);
            var::tmplPrmVars.clear();
        }

        template <typename ScannerT>
        inline void
        deriv_action_after_parse(
            ScannerT const& scan) const
        {
            var::tmplPrms=var::l_tmplPrms.back();
            var::l_tmplPrms.pop_back();
            var::tmplPrmVars=var::l_tmplPrmVars.back();
            var::l_tmplPrmVars.pop_back();
			var::parameterType = previousParameterType.back();
			previousParameterType.pop_back();
        }

		mutable std::list<eParameterType> previousParameterType;
    };

    template <typename ParserT>
    struct pdp
    :   public boost::spirit::classic::unary<ParserT, boost::spirit::classic::parser<pdp<ParserT> > > 
    {
        typedef pdp<ParserT>                     self_t;
        typedef boost::spirit::classic::unary_parser_category           parser_category_t;
        typedef boost::spirit::classic::unary<ParserT, boost::spirit::classic::parser<self_t> > base_t;

        pdp(ParserT const& p)
        : base_t(p) {}

        template <typename ScannerT>
        typename boost::spirit::classic::parser_result<self_t, ScannerT>::type
        parse(ScannerT const& scan) const
        {
            typedef typename boost::spirit::classic::parser_result<self_t, ScannerT>::type result_t;
            return impl::drt_parser_parse<result_t>
                (*this, scan, scan);
        }

        const char* MyName() const { return "pdp"; }

        template <typename ScannerT>
        inline void
        deriv_action_before_parse(
            ScannerT const& scan) const
        {
			previousParameterType.push_back(var::parameterType);
			var::parameterType = template_parameter;
			var::tmplPrmLevel++;
			if (var::tmplPrmLevel + 1 > static_cast<int>(var::tmplPrmNums.capacity()))
			{
				var::tmplPrmNums.resize(var::prmNums.size() + 5);
			}
			if (var::tmplPrmLevel + 1 > static_cast<int>(var::tmplPrmNums.size()))
				var::tmplPrmNums.push_back(0);
			else
  			    var::tmplPrmNums[var::tmplPrmLevel] = 0;
#if defined(CNOME_DEBUG)
            std::cout << "       pdp: var::tmplPrmlevel " << var::tmplPrmLevel << std::endl;
#endif
        }

        template <typename ScannerT>
        inline void
        deriv_action_after_parse(
            ScannerT const& scan) const
        {
			var::tmplPrmLevel--;
			var::parameterType = previousParameterType.back();
			previousParameterType.pop_back();
#if defined(CNOME_DEBUG)
            std::cout << "       pdp: var::tmplPrmlevel " << var::tmplPrmLevel << std::endl;
#endif
        }

		mutable std::list<eParameterType> previousParameterType;
    };

    //////////////////////////////////
    const drt_parser_gen<pdi> pdi_d = drt_parser_gen<pdi>();
    const drt_parser_gen<pdf> pdf_d = drt_parser_gen<pdf>();
    const drt_parser_gen<pdl> pdl_d = drt_parser_gen<pdl>();
    const drt_parser_gen<pdt> pdt_d = drt_parser_gen<pdt>();
    const drt_parser_gen<pdp> pdp_d = drt_parser_gen<pdp>();

}} // namespace cnome { namespace directive {

#endif  // DIRECTIVE_PD_H
